package com.woniuxy.shiro;

import com.woniuxy.entity.User;
import com.woniuxy.service.PermService;
import com.woniuxy.service.RoleService;
import com.woniuxy.service.UserService;
import com.woniuxy.utils.JWTUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;

import java.util.Arrays;
import java.util.List;

@Configuration
public class UserRealm extends AuthorizingRealm {
    @Autowired
    UserService userService;
    @Autowired
    RoleService roleService;
    @Autowired
    PermService permService;
    @Autowired
    RedisTemplate<String,Object> redisTemplate;

    //这里是shiro底层的问题，我们要手动重写底层的判断逻辑
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof MyJsonWebToken;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("----------------------开始执行授权-------------------------");
        //通过下面的认证方法SimpleAuthenticationInfo对象中的凭证获取到token的值！
        String token = principals.getPrimaryPrincipal()+"";
        String username = JWTUtils.getUsername(token);

        //使用username去数据库查出你的所有的角色和权限并封装到SimpleAuthorizationInfo
        User user = getUser(username);
        System.out.println("当前用户名："+user.getUsername());
        //获取用户对应的角色id
        String roleids = user.getRoles();
        System.out.println("当前用户拥有的角色id："+roleids);
        //定义一个角色集合数组
        String[] roleids_arr = roleids.split(",");
        System.out.println("当前用户拥有的角色id数组："+Arrays.toString(roleids_arr));
        //获取到角色名称集合
        List<String> roleList = getRoles(roleids_arr);
        if(roleList.size()!=0){
            System.out.println("当前用户拥有角色："+roleList);
            SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
            for(String role:roleList){
                //执行添加角色
                authorizationInfo.addRole(role);
                //权限信息
                List<String> perms = permService.findByUsername(username);
                System.out.println("当前用户拥有的权限："+perms.toString());
                authorizationInfo.addStringPermissions(perms);
            }
            return authorizationInfo;
        }
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken jwtToken) throws AuthenticationException {
        System.out.println("----------------开始执行认证------------------");
        //通过token获取我们自定义的MyJsonWebToken中存入的token
        String token = jwtToken.getPrincipal()+"";
        //从token中拿出用户名 后面篡改token的body值，来尝试，看能够获取到username，不先校验的情况
        String username = JWTUtils.getUsername(token);
        //如果token被篡改过，拿不到username
        if ("".equals(username)){
            throw new  AuthenticationException("用户信息不对！");
        }
        //获取user
        User user = getUser(username);
        //验证
        boolean verify = JWTUtils.verify(token, username, user.getPassword());
        if (verify){
           return new SimpleAuthenticationInfo(token,token,"UserRealm");
        }
        return null;
    }

    //获取user
    private User getUser(String username){
        //1、先去redis里找用户信息
        ValueOperations<String, Object> opsForValue = redisTemplate.opsForValue();
        User user=(User) opsForValue.get("user:"+username);
        //2、如果没有就查询数据库
        if (null==user) {
            System.out.println("user-查询数据库");
            user = userService.findByUsername(username);
            //存入redis
            opsForValue.set("user:"+username, user);
        }else{
            System.out.println("user-读取redis");
        }
        return user;
    }

    //获取roles
    private List<String> getRoles(String[] roleids_arr){
        //1、先去redis里找
        ValueOperations<String, Object> opsForValue = redisTemplate.opsForValue();
        List<String> roles= (List<String>) opsForValue.get("roles:"+ Arrays.toString(roleids_arr));
        //2、如果没有就查询数据库
        if (null==roles) {
            System.out.println("roles-查询数据库");
            roles = roleService.findByids(roleids_arr);
            System.out.println("查询数据库roles："+roles);
            //存入redis
            opsForValue.set("roles:"+Arrays.toString(roleids_arr), roles);
        }else{
            System.out.println("roles-读取redis");
        }
        return roles;
    }

    //获取perms
    private List<String> getPerms(String username){
        //1、先去redis里找
        ValueOperations<String, Object> opsForValue = redisTemplate.opsForValue();
        List<String> perms= (List<String>) opsForValue.get("perms:"+username);
        //2、如果没有就查询数据库
        if (null==perms) {
            System.out.println("perms-查询数据库");
            perms = permService.findByUsername(username);
            //存入redis
            opsForValue.set("perms:"+username, perms);
        }else{
            System.out.println("perms-读取redis");
        }
        return perms;
    }
}
